// att.cpp: implementation of the attributes class.
//
//////////////////////////////////////////////////////////////////////


#include <stdio.h>
#include <string.h>
#include <math.h>

#include "att.h"
#include "nodal_support.h"
#include "../draw.h"



// CreateAttribute
//////////////////////////////////////////////////////////////////////
acmF_Attribute *acmF_Attribute::CreateAttribute (int type)
{
 acmF_Attribute *Att = NULL;

  switch(type)
  {
    case CURVE_UNIFORM_FORCE:
     Att = new acmF_CurveForce; 
     strcpy (Att->AttName, "CURVE_UNIFORM_FORCE");
     break;

    case CURVE_SUPPORT:
     Att = new acmF_CurveSupport; 
     strcpy (Att->AttName, "CURVE_SUPPORT");
     break;

    case NODAL_FORCE:
     Att = new acmF_NodalForce; 
     strcpy (Att->AttName, "NODAL_FORCE");
     break;

    case NODAL_SUPPORT:
     Att = new acmF_NodalSupport; 
     strcpy (Att->AttName, "NODAL_SUPPORT");
     break;

    case FACE_PROPER:
     Att = new acmF_MatLinProper; 
     strcpy (Att->AttName, "FACE_PROPER");
     break;
  }

  return(Att);
}

// CreateAttribute
//////////////////////////////////////////////////////////////////////
acmF_Attribute *acmF_Attribute::CreateAttribute (char *type)
{
  acmF_Attribute *Att = NULL;

  if (strcmp (type, "CURVE_UNIFORM_FORCE") == 0)
  {
     Att = new acmF_CurveForce; 
     strcpy (Att->AttName, "CURVE_UNIFORM_FORCE");
  }
  else if (strcmp (type, "CURVE_SUPPORT") == 0)
  {
     Att = new acmF_CurveSupport; 
     strcpy (Att->AttName, "CURVE_SUPPORT");
  }
  else if (strcmp (type, "NODAL_FORCE") == 0)
  {
     Att = new acmF_NodalForce; 
     strcpy (Att->AttName, "NODAL_FORCE");
  }
  else if (strcmp (type, "NODAL_SUPPORT") == 0)
  {
     Att = new acmF_NodalSupport; 
     strcpy (Att->AttName, "NODAL_SUPPORT");
  }
  else if (strcmp (type, "FACE_PROPER") == 0)
  {
     Att = new acmF_MatLinProper; 
     strcpy (Att->AttName, "FACE_PROPER");
  }
  return(Att);
}

//
//////////////////////////////////////////////////////////////////////////
void acmF_Attribute::drawSupport1( double *p, double size, double ang )
{
  double line1[6],line2[4],line3[4];	/* aux. variables to draw the 	*/
  int    npointsL1,npointsL2,npointsL3;	/* support			*/

  if (m_pDrawObj == NULL)
    return;

  /* Build the support (triangle)						*/

  line1 [0] = ( p[0] ) - ( size * 0.33333 );
  line1 [1] = ( p[1] ) - ( size * 0.57735 );
  line1 [2] = ( p[0] );
  line1 [3] = ( p[1] );
  line1 [4] = ( p[0] ) + ( size * 0.33333 );
  line1 [5] = line1 [1];
  npointsL1 = 3;

  line2 [0] = line1 [0] - ( size * 0.16666 );
  line2 [1] = line1 [1];
  line2 [2] = line1 [4] + ( size * 0.16666 );
  line2 [3] = line1 [1];
  npointsL2 = 2;

  line3 [0] = line2 [0];
  line3 [1] = line1 [1] - ( size * 0.2 );
  line3 [2] = line2 [2];
  line3 [3] = line3 [1];
  npointsL3 = 2;

  /* Rotate the points to correct position based on the given angle	*/

  rotatePoints ( ang, p, line1, npointsL1 );
  rotatePoints ( ang, p, line2, npointsL2 );
  rotatePoints ( ang, p, line3, npointsL3 );

  /* Drawing the support							*/

  m_pDrawObj->PolyLine ( npointsL1, line1 );
  m_pDrawObj->PolyLine ( npointsL2, line2 );
  m_pDrawObj->PolyLine ( npointsL3, line3 );
}

//
//////////////////////////////////////////////////////////////////////////
void acmF_Attribute::drawSupport2( double *pts, double size, double ang )
{
  double line1[6],line2[4],linehatch[4];	/* aux. variables to draw the 	*/
  int    npointsL1,npointsL2,npointsLh;	/* support			*/
  double auxlh[4];
  int    i;

  /* Build the support (triangle)						*/

  line1 [0] = ( pts[0] ) - ( size * 0.33333 );
  line1 [1] = ( pts[1] ) - ( size * 0.57735 );
  line1 [2] = ( pts[0] );
  line1 [3] = ( pts[1] );
  line1 [4] = ( pts[0] ) + ( size * 0.33333 );
  line1 [5] = line1 [1];
  npointsL1 = 3;

  line2 [0] = line1 [0] - ( size * 0.16666 );
  line2 [1] = line1 [1];
  line2 [2] = line1 [4] + ( size * 0.16666 );
  line2 [3] = line1 [1];
  npointsL2 = 2;

  linehatch [0] = line2 [0] + ( size * 0.2 );
  linehatch [1] = line2 [1];
  linehatch [2] = line2 [0];
  linehatch [3] = line2 [1] - ( size * 0.2 );
  npointsLh = 2;

  /* Rotate the points to correct position based on the given angle	*/

  rotatePoints ( ang, pts, line1, npointsL1 );
  rotatePoints ( ang, pts, line2, npointsL2 );

  /* Drawing the support							*/

  m_pDrawObj->PolyLine ( npointsL1, line1 );
  m_pDrawObj->PolyLine ( npointsL2, line2 );

  /* Drawing the support hatch						*/

  auxlh [0] = linehatch [0];
  auxlh [1] = linehatch [1];
  auxlh [2] = linehatch [2];
  auxlh [3] = linehatch [3];

  for ( i=1; i<6; i++ ) {

    rotatePoints ( ang, pts, linehatch, npointsLh );
    m_pDrawObj->PolyLine ( npointsLh, linehatch );
    linehatch [0] = auxlh [0] + ( size * 0.2 * i );
    linehatch [1] = auxlh [1];
    linehatch [2] = auxlh [2] + ( size * 0.2 * i );
    linehatch [3] = auxlh [3];
  }
}

//
//////////////////////////////////////////////////////////////////////////
void acmF_Attribute::drawSupport3( double *pts, double size, double ang )
{
  double line[4],linehatch[4];		/* aux. variables to draw the 	*/
  int    npointsL,npointsLh;		/* support			*/
  double auxlh[4];
  int    i;

  /* Build the support (line)						*/

  line [0] = ( pts[0] ) - ( size * 0.5 );
  line [1] = ( pts[1] );
  line [2] = ( pts[0] ) + ( size * 0.5 );
  line [3] = ( pts[1] );
  npointsL = 2;

  linehatch [0] = line [0] + ( size * 0.2 );
  linehatch [1] = line [1];
  linehatch [2] = line [0];
  linehatch [3] = line [1] - ( size * 0.2 );
  npointsLh = 2;

  /* Rotate the points to correct position based on the given angle	*/

  rotatePoints ( ang, pts, line, npointsL );

  /* Drawing the support							*/

  m_pDrawObj->PolyLine ( npointsL, line );

  /* Drawing the support hatch						*/

  auxlh [0] = linehatch [0];
  auxlh [1] = linehatch [1];
  auxlh [2] = linehatch [2];
  auxlh [3] = linehatch [3];

  for ( i=1; i<6; i++ ) {

    rotatePoints ( ang, pts, linehatch, npointsLh );
    m_pDrawObj->PolyLine ( npointsLh, linehatch );
    linehatch [0] = auxlh [0] + ( size * 0.2 * i );
    linehatch [1] = auxlh [1];
    linehatch [2] = auxlh [2] + ( size * 0.2 * i );
    linehatch [3] = auxlh [3];
  }
}


//
//////////////////////////////////////////////////////////////////////////
void acmF_Attribute::rotatePoints( double ang, double *p, double *pts, int npts )
{
  double	T[3][3];
  double	P[3];
  double	TP[3];
  int 	i,n;

  /* Fills the rotation matrix						*/

  T [0][0] = cos ( ang );
  T [0][1] = -sin ( ang );
  T [0][2] = ( -(p[0]) * cos ( ang ) ) + ( p[1] * sin ( ang ) ) + ( p[0] );
  T [1][0] = sin ( ang );
  T [1][1] = cos ( ang );
  T [1][2] = ( -(p[0]) * sin ( ang ) ) - ( p[1] * cos ( ang ) ) + ( p[1] );
  T [2][0] = 0;
  T [2][1] = 0;
  T [2][2] = 1;

  n = 3;

  /* For each given point rotate it to the correct position		*/
  for (i = 0; i < npts; i++ ) 
  {

    P [0] = pts[i*2+0];
    P [1] = pts[i*2+1];
    P [2] = 1;


    matrixMultVector ( n, n, n,T,P,TP );

    TP [0] = ( TP [0] ) / ( TP [2] );
    TP [1] = ( TP [1] ) / ( TP [2] );
    TP [2] = ( TP [2] ) / ( TP [2] );
    pts[i*2+0] = TP [0];
    pts[i*2+1] = TP [1];
  }
}

//
//////////////////////////////////////////////////////////////////////////
void 
acmF_Attribute::matrixMultVector (int MA, int NA, int MB, double	A[3][3],
                                  double	B[3], double	AB[3])
{
  int 	i, j;
  double 	sum;

  if ( MB == NA ) 
  {
    for ( i=0; i<MA; i++ ) 
    {
      sum = 0;
      for ( j=0; j<MB; j++ ) 
        sum += (A[i][j]) * (B[j]);
      AB[i] = sum;
    }
  }
  else 
  {
    for ( i=0; i<MA; i++ )
      AB[i] = 0;
  }
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// acmF_CurveForce
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////


// acmF_CurveForce
//////////////////////////////////////////////////////////////////////
acmF_CurveForce::acmF_CurveForce(void)
{
}

// acmF_CurveForce
//////////////////////////////////////////////////////////////////////
acmF_CurveForce::~acmF_CurveForce(void)
{
}


// acmF_CurveForce::Read
//////////////////////////////////////////////////////////////////////
void acmF_CurveForce::Read (FILE *ptr_file)
{
  fscanf(ptr_file, "%lf %lf %lf", &qx, &qy, &qz);
  fscanf(ptr_file, "%lf %lf %lf %d", &mx, &my, &mz, &system);
}


// acmF_CurveForce::Save
//////////////////////////////////////////////////////////////////////
void acmF_CurveForce::Save (FILE *ptr_file)
{
  fprintf(ptr_file, "%lf %lf %lf ", qx, qy, qz);
  fprintf(ptr_file, "%lf %lf %lf %d", mx, my, mz, system);
}

// acmF_CurveForce::SetParam
//////////////////////////////////////////////////////////////////////
void acmF_CurveForce::SetParam (double *param)
{
  qx = param[0];
  qy = param[1];
  qz = param[2];
  mx = param[3];
  my = param[4];
  mz = param[5];
  system = int (param[6]);
}

// acmF_CurveForce::GetParam
//////////////////////////////////////////////////////////////////////
void acmF_CurveForce::GetParam (int *np, double **param)
{
  *np = 7;

  *param = new double [7];
 
  (*param)[0] = qx;
  (*param)[1] = qy;
  (*param)[2] = qz;
  (*param)[3] = mx;
  (*param)[4] = my;
  (*param)[5] = mz;
  (*param)[6] = system;
}

// acmF_CurveForce::Copy
//////////////////////////////////////////////////////////////////////
acmF_Attribute *acmF_CurveForce::Copy (void)
{
  double *param;
  int    num_par;
  acmF_CurveForce *copyatt = new acmF_CurveForce;

  GetParam (&num_par, &param);
  copyatt->SetParam (param);
  strcpy (copyatt->AttName, AttName);
  return (copyatt);
}



//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// acmF_CurveSupport
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////


// acmF_CurveSupport
//////////////////////////////////////////////////////////////////////
acmF_CurveSupport::acmF_CurveSupport (void)
{
}

// acmF_CurveSupport
//////////////////////////////////////////////////////////////////////
acmF_CurveSupport::~acmF_CurveSupport (void)
{
}

// acmF_CurveSupport::Read
//////////////////////////////////////////////////////////////////////
void acmF_CurveSupport::Read (FILE *ptr_file)
{
  fscanf(ptr_file, "%d %d %d", &sup[0], &sup[1], &sup[2]);
  fscanf(ptr_file, "%d %d %d", &sup[3], &sup[4], &sup[5]);
}


// acmF_CurveSupport::Save
//////////////////////////////////////////////////////////////////////
void acmF_CurveSupport::Save (FILE *ptr_file)
{
  fprintf(ptr_file, "%d %d %d ", sup[0], sup[1], sup[2]);
  fprintf(ptr_file, "%d %d %d", sup[3], sup[4], sup[5]);
}

// acmF_CurveSupport::SetParam
//////////////////////////////////////////////////////////////////////
void acmF_CurveSupport::SetParam (double *param)
{
  sup[0] = int (param[0]);
  sup[1] = int (param[1]);
  sup[2] = int (param[2]);
  sup[3] = int (param[3]);
  sup[4] = int (param[4]);
  sup[5] = int (param[5]);
}

// acmF_CurveSupport::GetParam
//////////////////////////////////////////////////////////////////////
void acmF_CurveSupport::GetParam (int *np, double **param)
{
  *np = 6;

  *param = new double [6];
 
  (*param)[0] = sup[0];
  (*param)[1] = sup[1];
  (*param)[2] = sup[2];
  (*param)[3] = sup[3];
  (*param)[4] = sup[4];
  (*param)[5] = sup[5];
}

// acmF_CurveSupport::Copy
//////////////////////////////////////////////////////////////////////
acmF_Attribute *acmF_CurveSupport::Copy (void)
{
  double *param;
  int    num_par;
  acmF_CurveSupport *copyatt = new acmF_CurveSupport;

  GetParam (&num_par, &param);
  copyatt->SetParam (param);
  strcpy (copyatt->AttName, AttName);
  return (copyatt);
}


// Draw
//////////////////////////////////////////////////////////////////////
void acmF_CurveSupport::Draw( int npts, double *pts )
{
  if (m_pDrawObj == NULL)
    return;

  int type;
  double angle;

  // set type of support
  if (sup[0] == 1 && sup[1] == 0)
  {
    type = 1; angle = 3.1416/2.0;
  }
  else if (sup[0] == 0 && sup[1] == 1)
  {
    type = 1; angle = 0.0;
  }
  else if (sup[0] == 1 && sup[1] == 1)
  {
    type = 2; angle = 0.0;
  }
  else if (sup[0] == 1 && sup[1] == 1 && sup[3] == 1)
  {
    type = 3; angle = 0.0;
  }

  // length e spaces
  double size = m_pDrawObj->ref_size * DSP_SUPPORT_FAC;
  double L = 0.0;
  for (int i = 1; i < npts; ++i)
  {
    double dx = pts[i*2+0] - pts[(i-1)*2+0];
    double dy = pts[i*2+0] - pts[(i-1)*2+0];
    L += sqrt (dx*dx + dy*dy);
  }
  int n_spaces = (int) (L /  (size*1.4));

  // internal narrows
  if (n_spaces > 1)
  {
    double curr_l = 0.0, step_l = 0.0, space_supp = L / (n_spaces*1.0);
    double delta;
    int    curr_supp = 1;
    double p[2];

    for (int i = 0; i < npts-1; i++)
    {
      step_l = sqrt (((pts[(i+1)*2+0]-pts[i*2+0]) * (pts[(i+1)*2+0]-pts[i*2+0])) + 
                     ((pts[(i+1)*2+1]-pts[i*2+1]) * (pts[(i+1)*2+1]-pts[i*2+1])));
      while (((curr_supp*space_supp) > curr_l) &&
             ((curr_supp*space_supp) <= (curr_l + step_l)) )
      {
        delta = (curr_supp*space_supp - curr_l) / step_l;
        p[0] = pts[i*2+0] + (pts[(i+1)*2+0] - pts[i*2+0]) * delta;
        p[1] = pts[i*2+1] + (pts[(i+1)*2+1] - pts[i*2+1]) * delta;

        if ((i == npts-2) && (((curr_supp+1) * space_supp) > (curr_l + step_l)) )
          break;

        switch (type)
        {
        case 1 : drawSupport1 (p, size, angle );
          break;
        case 2 : drawSupport2 (p, size, angle );
          break;
        case 3 : drawSupport3 (p, size, angle );
          break;
        default :
          break;
        }

        curr_supp++;
      }

      curr_l += step_l;
    }
  }

}




//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// acmF_NodalForce
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

// acmF_NodalForce
//////////////////////////////////////////////////////////////////////
acmF_NodalForce::acmF_NodalForce (void)
{
}


// acmF_NodalForce
//////////////////////////////////////////////////////////////////////
acmF_NodalForce::~acmF_NodalForce (void)
{
}


// acmF_NodalForce::Read
//////////////////////////////////////////////////////////////////////
void acmF_NodalForce::Read (FILE *ptr_file)
{
  fscanf( ptr_file, "%lf %lf %lf", &fx, &fy, &fz);
  fscanf( ptr_file, "%lf %lf %lf", &mx, &my, &mz);
}


// acmF_NodalForce::Save
//////////////////////////////////////////////////////////////////////
void acmF_NodalForce::Save (FILE *ptr_file)
{
  fprintf( ptr_file, "%lf %lf %lf ", fx, fy, fz);
  fprintf( ptr_file, "%lf %lf %lf", mx, my, mz);
}

// acmF_NodalForce::SetParam
//////////////////////////////////////////////////////////////////////
void acmF_NodalForce::SetParam (double *param)
{
  fx = param[0];
  fy = param[1];
  fz = param[2];
  mx = param[3];
  my = param[4];
  mz = param[5];
}

// acmF_NodalForce::GetParam
//////////////////////////////////////////////////////////////////////
void acmF_NodalForce::GetParam (int *np, double **param)
{
  *np = 6;

  *param = new double [6];
 
  (*param)[0] = fx;
  (*param)[1] = fy;
  (*param)[2] = fz;
  (*param)[3] = mx;
  (*param)[4] = my;
  (*param)[5] = mz;
}

// acmF_NodalForce::Copy
//////////////////////////////////////////////////////////////////////
acmF_Attribute *acmF_NodalForce::Copy (void)
{
  double *param;
  int    num_par;
  acmF_NodalForce *copyatt = new acmF_NodalForce;

  GetParam (&num_par, &param);
  copyatt->SetParam (param);
  strcpy (copyatt->AttName, AttName);
  return (copyatt);
}





//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// acmF_NodalSupport
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

#if 0

// acmF_NodalSupport
//////////////////////////////////////////////////////////////////////
acmF_NodalSupport::acmF_NodalSupport (void)
{
}

// acmF_NodalSupport
//////////////////////////////////////////////////////////////////////
acmF_NodalSupport::~acmF_NodalSupport (void)
{
}


// acmF_NodalSupport::Read
//////////////////////////////////////////////////////////////////////
void acmF_NodalSupport::Read (FILE *ptr_file)
{
  fscanf(ptr_file, "%d %d %d", &sup[0], &sup[1], &sup[2]);
  fscanf(ptr_file, "%d %d %d", &sup[3], &sup[4], &sup[5]);
}


// acmF_NodalSupport::Save
//////////////////////////////////////////////////////////////////////
void acmF_NodalSupport::Save (FILE *ptr_file)
{
  fprintf(ptr_file, "%d %d %d ", sup[0], sup[1], sup[2]);
  fprintf(ptr_file, "%d %d %d", sup[3], sup[4], sup[5]);
}

// acmF_NodalSupport::SetParam
//////////////////////////////////////////////////////////////////////
void acmF_NodalSupport::SetParam (double *param)
{
  sup[0] = int (param[0]);
  sup[1] = int (param[1]);
  sup[2] = int (param[2]);
  sup[3] = int (param[3]);
  sup[4] = int (param[4]);
  sup[5] = int (param[5]);
}

// acmF_NodalSupport::GetParam
//////////////////////////////////////////////////////////////////////
void acmF_NodalSupport::GetParam (int *np, double **param)
{
  *np = 6;

  *param = new double [6];

  (*param)[0] = sup[0];
  (*param)[1] = sup[1];
  (*param)[2] = sup[2];
  (*param)[3] = sup[3];
  (*param)[4] = sup[4];
  (*param)[5] = sup[5];
}

// acmF_NodalSupport::Copy
//////////////////////////////////////////////////////////////////////
acmF_Attribute *acmF_NodalSupport::Copy (void)
{
  double *param;
  int    num_par;
  acmF_CurveSupport *copyatt = new acmF_CurveSupport;

  GetParam (&num_par, &param);
  copyatt->SetParam (param);
  strcpy (copyatt->AttName, AttName);
  return (copyatt);
}

#endif


//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// acmF_FaceProper
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

// acmF_FaceProper
//////////////////////////////////////////////////////////////////////
acmF_MatLinProper::acmF_MatLinProper (void)
{
}

// acmF_FaceProper
//////////////////////////////////////////////////////////////////////
acmF_MatLinProper::~acmF_MatLinProper (void)
{
}


// acmF_CurveCrack::Read
//////////////////////////////////////////////////////////////////////
void acmF_MatLinProper::Read (FILE *ptr_file)
{
  fscanf (ptr_file, "%lf %lf", &E, &nu);
}


// acmF_CurveCrack::Save
//////////////////////////////////////////////////////////////////////
void acmF_MatLinProper::Save (FILE *ptr_file)
{
  fprintf (ptr_file, "%lf\t%lf", E, nu);
}

// acmF_CurveCrack::SetParam
//////////////////////////////////////////////////////////////////////
void acmF_MatLinProper::SetParam (double *param)
{
  E         = param[0];
  nu        = param[1];
}

// acmF_CurveCrack::GetParam
//////////////////////////////////////////////////////////////////////
void acmF_MatLinProper::GetParam (int *np, double **param)
{
  *np = 2;

  *param = new double [2];

  (*param)[0] = E;
  (*param)[1] = nu;
}

// acmF_FaceProper::Copy
//////////////////////////////////////////////////////////////////////
acmF_Attribute *acmF_MatLinProper::Copy (void)
{
  double *param;
  int    num_par;
  acmF_MatLinProper *copyatt = new acmF_MatLinProper;

  GetParam (&num_par, &param);
  copyatt->SetParam (param);
  strcpy (copyatt->AttName, AttName);

  return (copyatt);
}
